package performance;

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author long
 */
public class MultiQueryCase {

    private static final Executor executor = Executors.newFixedThreadPool(10);

    /**
     * 使用FutureTask实现并发分页查询
     */
    @Test
    public void test1(){
        int size = 5000;

        // 模拟查询产品编码数据
        List<Integer> productCodeList = getProductCodeFromDb(size);

        long start = System.currentTimeMillis();
        List<Product> productList;
        if(productCodeList.size()<= 500){
            productList = getProductFromRpc(productCodeList);
        }else{
            List<List<Integer>> partProductList = Lists.partition(productCodeList,500);
            List<FutureTask<List<Product>>> futureTaskList = partProductList.stream()
                    .map(partList-> new FutureTask<>(()-> getProductFromRpc(partList))).collect(Collectors.toList());

            futureTaskList.forEach(executor::execute);
            productList = futureTaskList.stream().map(this::getResultOfFuture)
                    .filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
        }
        System.out.println("数量："+productList.size()+" 耗时："+(System.currentTimeMillis()-start)+" ms");
    }

    @Test
    public void test2(){
        int size = 5000;

        // 模拟查询产品编码数据
        List<Integer> productCodeList = getProductCodeFromDb(size);

        long start = System.currentTimeMillis();
        List<Product> productList;
        if(productCodeList.size()<= 500){
            productList = getProductFromRpc(productCodeList);
        }else{
            List<List<Integer>> partProductList = Lists.partition(productCodeList,500);
            List<CompletableFuture<List<Product>>> futureTaskList = partProductList.stream()
                    .map(partList-> CompletableFuture.supplyAsync(()-> getProductFromRpc(partList),executor))
                    .collect(Collectors.toList());

            productList = futureTaskList.stream().map(CompletableFuture::join)
                    .filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());
        }
        System.out.println("数量："+productList.size()+" 耗时："+(System.currentTimeMillis()-start)+" ms");
    }

    private List<Integer> getProductCodeFromDb(int size){
        return IntStream.rangeClosed(1,size).boxed().collect(Collectors.toList());
    }

    private List<Product> getProductFromRpc(List<Integer> codeList){
        // 睡眠1s
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return codeList.stream().map(code->
                Product.builder().productCode(code).productName("name"+code).build()).collect(Collectors.toList());
    }

    private List<Product> getResultOfFuture(FutureTask<List<Product>> futureTask){
        try {
            return futureTask.get();
        } catch (InterruptedException | ExecutionException e) {
            return null;
        }
    }

}
